package belf.migrate.engine.ddl.procedure.oracle;

import belf.migrate.core.jdbc.FunctionModel;
import belf.migrate.core.jdbc.TypeModel;
import belf.migrate.core.util.StringTool;
import belf.migrate.engine.ddl.BaseDDLConvert;
import belf.migrate.plugin.oracle.antlr.PlSqlParser;
import belf.migrate.plugin.oracle.antlr.PlSqlParserBaseVisitor;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 基于antlr解析的Oracle存储过程的语法树，重构sql语句的辅助类
 */
public class OracleProcedureVistor extends PlSqlParserBaseVisitor<String> {
    //以下5个参数为构造参数
    private BaseDDLConvert ddlConvert;
    private String quote = "\"";
    private String schema;
    private Map<String, FunctionModel> funcMapping;
    private Map<String, TypeModel> typeMapping;

    //存储过程名称
    private String procedureName;
    //参数列表
    private List<PlSqlParser.ParameterContext> parameters;
    //存储过程结尾的标签（END之后的）。可以没有
    private String procedureLableName;
    // 申明的局部变量
    private List<PlSqlParser.Declare_specContext> variables;
    // BEGIN...END之间的过程定义语句
    private List<PlSqlParser.StatementContext> procedureSqls;

    public OracleProcedureVistor(BaseDDLConvert ddlConvert,
                                 String quote,
                                 String schema,
                                 Map<String, FunctionModel> funcMapping,
                                 Map<String, TypeModel> typeMapping) {
        this.ddlConvert = ddlConvert;
        this.quote = quote;
        this.schema = schema;
        this.funcMapping = funcMapping;
        this.typeMapping = typeMapping;

        parameters = new ArrayList<>();
        variables = new ArrayList<>();
        procedureSqls = new ArrayList<>();
    }

    @Override
    public String visitCreate_procedure_body(PlSqlParser.Create_procedure_bodyContext ctx) {
        //存储过程名称，需要加上schema，并加上引号
        procedureName = ctx.procedure_name().getText().trim();
        if (procedureName.indexOf('.') == -1) {
            procedureName = StringTool.addQuote(schema, quote) + "." + StringTool.addQuote(procedureName, quote);
        }
        //存储过程的参数
        parameters.addAll(ctx.parameter());

        //BEGIN...END中间的存储过程定义语句列表
        procedureSqls.addAll(ctx.body().seq_of_statements().statement());
        return visitChildren(ctx);
    }

    @Override
    public String visitSeq_of_declare_specs(PlSqlParser.Seq_of_declare_specsContext ctx) {
        if (ctx != null && ctx.declare_spec() != null) {
            variables.addAll(ctx.declare_spec());  //找到定义的变量，可能在BEGIN之前或之后
        }
        return visitChildren(ctx);
    }

    @Override
    public String visitLabel_name(PlSqlParser.Label_nameContext ctx) {
        if (ctx.getParent() instanceof PlSqlParser.BodyContext) {
            procedureLableName = ctx.getText();
        }
        return visitChildren(ctx);
    }

    public String getProcedureName() {
        return procedureName;
    }

    public String getProcedureLableName() {
        if (null == procedureLableName) {
            return "";
        }
        return procedureLableName;
    }

    public List<PlSqlParser.ParameterContext> getParameters() {
        return parameters;
    }


    public List<PlSqlParser.Declare_specContext> getVariables() {
        return variables;
    }

    public List<PlSqlParser.StatementContext> getProcedureSqls() {
        return procedureSqls;
    }
}
